package com.lambkit.core;

import com.lambkit.core.pipeline.IPipeLineFactory;
import com.lambkit.core.pipeline.PipeLineService;
import com.lambkit.core.service.*;
import com.lambkit.util.Printer;

/**
 * 应用运行类
 * @author yangyong(孤竹行)
 */
public abstract class LambkitApp implements Lifecycle {

    /**
     * 上下文
     */
    private AppContext context;

    private boolean started = false;

    private LifecycleState state = LifecycleState.NEW;

    public LambkitApp() {
        this.context = new AppContext(Lambkit.createName(this.getClass()));
    }
    public LambkitApp(String name) {
        this.context = new AppContext(name);
    }

    public LambkitApp(AppContext context) {
        this.context = context;
    }

    /////////////////////////////////////////////////////

    /**
     * app是否已经准备好
     * @return
     */
    public boolean isReady() {
        if(context()==null) {
            return false;
        }
        if(getBeanFactory()==null) {
            return false;
        }
        if (getClassOperateFactory()==null) {
            return false;
        }
        if (getResourceFactory()==null) {
            return false;
        }
        if (getPipeLineFactory()==null) {
            return false;
        }
        return true;
    }

    @Override
    public LifecycleState getCurrentState() {
        return state;
    }

    @Override
    public void init() throws LifecycleException {
        state = LifecycleState.INITIALIZING;
        //启动，设置配置，建立管道
        context.getConfigList().forEach(c -> {
            try {
                c.setContext(context);
                c.init();
                Printer.print(this, "starter", "Init Config: " + c.getClass().getName());
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        //启动，设置模块等
        context.getLifecycleList().forEach(c -> {
            try {
                c.setContext(context);
                c.init();
                Printer.print(this, "starter", "Init lifecycle: " + c.getClass().getName());
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        //启动，设置插件
        context.getPlugins().getPluginList().forEach(c -> {
            try {
                c.setContext(context);
                c.init();
                Printer.print(this, "starter", "Init Plugin: " + c.getClass().getName());
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        if(context.getFlowWorkCenter() != null) {
            context.getFlowWorkCenter().start();
        }
        context.getWorkCenters().values().stream().forEach(c -> {
            try {
                c.init();
                Printer.print(this, "starter", "Init WorkCenter: " + c.getClass().getName());
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        state = LifecycleState.INITIALIZED;
    }

    @Override
    public void start() throws LifecycleException {
        state = LifecycleState.STARTING;
        //启动，设置配置，建立管道
        context.getConfigList().forEach(c -> {
            try {
                //c.setContext(context);
                c.start();
                Printer.print(this, "starter", "Start Config: " + c.getClass().getName());
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        //启动，设置插件
        context.getLifecycleList().forEach(c -> {
            try {
                //c.setContext(context);
                c.start();
                Printer.print(this, "starter", "Start lifecycle: " + c.getClass().getName());
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        //启动，设置插件
        context.getPlugins().getPluginList().forEach(c -> {
            try {
                c.setContext(context);
                c.start();
                Printer.print(this, "starter", "Start Plugin: " + c.getClass().getName());
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        if(context.getFlowWorkCenter() != null) {
            context.getFlowWorkCenter().start();
        }
        context.getWorkCenters().values().stream().forEach(c -> {
            try {
                c.start();
                Printer.print(this, "starter", "Start WorkCenter: " + c.getClass().getName());
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        state = LifecycleState.STARTED;
    }

    @Override
    public void postStart() throws LifecycleException {
        Lifecycle.super.postStart();
        context.getConfigList().forEach(c -> {
            try {
                c.postStart();
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        // 运行之后
        context.getLifecycleList().forEach(c -> {
            try {
                c.postStart();
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        context.getPlugins().getPluginList().forEach(c -> {
            try {
                c.postStart();
                Printer.print(this, "starter", "Start Plugin: " + c.getClass().getName());
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        if(context.getFlowWorkCenter() != null) {
            context.getFlowWorkCenter().postStart();
        }
        context.getWorkCenters().values().stream().forEach(c -> {
            try {
                c.postStart();
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        started = true;
    }

    @Override
    public void preStop() throws LifecycleException {
        Lifecycle.super.preStop();
        state = LifecycleState.STOPPING_PREP;
        if(context.getFlowWorkCenter() != null) {
            context.getFlowWorkCenter().preStop();
        }
        context.getWorkCenters().values().stream().forEach(c -> {
            try {
                c.preStop();
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        context.getPlugins().getPluginList().forEach(c -> {
            try {
                c.preStop();
                Printer.print(this, "starter", "Start Plugin: " + c.getClass().getName());
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        context.getLifecycleList().forEach(c -> {
            try {
                c.preStop();
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        context.getConfigList().forEach(c -> {
            try {
                c.preStop();
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
    }

    @Override
    public void stop() throws LifecycleException {
        Lifecycle.super.stop();
        state = LifecycleState.STOPPING;
        if(context.getFlowWorkCenter() != null) {
            context.getFlowWorkCenter().stop();
        }
        context.getWorkCenters().values().stream().forEach(c -> {
            try {
                c.stop();
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        context.getPlugins().getPluginList().forEach(c -> {
            try {
                c.stop();
                Printer.print(this, "starter", "Start Plugin: " + c.getClass().getName());
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        // 关闭模块
        context.getLifecycleList().forEach(c -> {
            try {
                c.stop();
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        context.getConfigList().forEach(c -> {
            try {
                c.stop();
            } catch (LifecycleException e) {
                throw new RuntimeException(e);
            }
        });
        state = LifecycleState.STOPPED;
    }

    public synchronized void restart() {
        if (this.started) {
            this.started = false;
            try {
                this.preStop();
                this.stop();
                this.start();
                this.postStart();
            } catch (Exception exception) {
                exception.printStackTrace();
            }
        }
    }

    public <T> T getBean(Class<T> clazz) {
        return context.getBean(clazz);
    }
    ///////////////////////////////////////////////////////

    public AppContext context() {
        return context;
    }

    public ClassOperateService classOperateService() {
        return getClassOperateFactory().getClassOperateService();
    }

    public ResourceService resourceService() {
        return getResourceFactory().getResourceService();
    }

    public PipeLineService pipeLineService() {
        return getPipeLineFactory().getPipeLineService();
    }

    public BeanFactory getBeanFactory() {
        return context().getBeanFactory();
    }

    public ClassOperateFactory getClassOperateFactory() {
        return context().getClassOperateFactory();
    }

    public IPipeLineFactory getPipeLineFactory() {
        return context().getPipeLineFactory();
    }

    public ResourceFactory getResourceFactory() {
        return context().getResourceFactory();
    }

    public boolean isStarted() {
        return started;
    }
}
